
#include "Sprite3D.h"
#include "CCTexture2D.h"
#include "math.h"



Sprite3D::Sprite3D()
{
	
}

Sprite3D::~Sprite3D(void)
{
	
}
int angle = 90;
void Sprite3D::draw(void)
{
	GetVerticesAt( m_TimeMS );

	float scale = 2.0f;
	glTranslatef( 200, 200, 100 );
	glScalef( scale, scale, scale );
	glRotatef( 180, 0, 0, 1 );
	glRotatef( angle, 0, 1, 0 );
	glRotatef( 90, 1, 0, 0 );

	glDisableClientState( GL_COLOR_ARRAY );

	if (m_pobTexture)
	{
		glBindTexture(GL_TEXTURE_2D, m_pobTexture->getName());
	}
	else
	{
		glBindTexture(GL_TEXTURE_2D, 0);
	}

	glVertexPointer( 3, GL_FLOAT, 0, &m_BufferVertices[0] );
	glTexCoordPointer( 2, GL_FLOAT, 0, &m_TextureVertices[0] );
	glDrawElements( GL_TRIANGLE_STRIP, m_IndexCount, GL_UNSIGNED_SHORT, &m_Indicies[0] );


}

void Sprite3D::update(ccTime delta)
{
	m_TimeMS += delta*1000;

	const int timeStartMS = m_Frames[m_FrameStart].timeMS;
	const int timeEndMS = m_Frames[m_FrameEnd].timeMS;
	const int rangeMS = timeEndMS - timeStartMS;

	if( rangeMS == 0 )
		m_TimeMS = timeStartMS;
	else if( m_TimeMS > timeEndMS )
	{
		const int overflowMS = ( m_TimeMS - timeEndMS ) % rangeMS;
		m_TimeMS = timeStartMS + overflowMS;
	}

}

Sprite3D* Sprite3D::spriteWithFile(const char *pszFileName, const char *meshFilename)
{
	Sprite3D *pobSprite = new Sprite3D();
	if (pobSprite && pobSprite->initWith3DFile(pszFileName, meshFilename))
	{
		pobSprite->autorelease();
		return pobSprite;
	}
	CC_SAFE_DELETE(pobSprite);
	return NULL;
}


bool Sprite3D::initWith3DFile(const char *pszFilename, const char *meshFilename)
{
	assert(pszFilename != NULL && meshFilename != NULL);

	CCTexture2D *pTexture = CCTextureCache::sharedTextureCache()->addImage(pszFilename);
	if (pTexture)
	{
		CCRect rect = CCRectZero;
		rect.size = pTexture->getContentSize();

		unsigned char * m_pBuffer;
		unsigned long m_uSize;
		
		std::string pathKey = meshFilename;
		CCFileUtils::ccRemoveHDSuffixFromFile(pathKey);
		pathKey = CCFileUtils::fullPathFromRelativePath(pathKey.c_str());
		
		m_pBuffer = CCFileUtils::getFileData(pathKey.c_str(), "r", &m_uSize);
		
		assert(m_pBuffer);

		ReadUInt8( &m_pBuffer );

		m_IndexCount = ReadUInt32( &m_pBuffer );
		m_NodeCount = ReadUInt8( &m_pBuffer );
		m_FrameCount = ReadUInt16( &m_pBuffer );
		m_VertexCount = ReadUInt16( &m_pBuffer );

		for( unsigned i = 0; i < m_NodeCount; ++i )
		{
			int ByteCount = ReadUInt8( &m_pBuffer );
			ReadSkip( &m_pBuffer,ByteCount );
		}

		for( unsigned i = 0; i < m_IndexCount; ++i )
		{
			m_Indicies[i] = ReadUInt16( &m_pBuffer );
		}

		for( unsigned i = 0; i < m_VertexCount; ++i )
		{
			m_TextureVertices[i * 2] = ReadFloat( &m_pBuffer );
			m_TextureVertices[i * 2 + 1] = 1.0 - ReadFloat( &m_pBuffer );
		}

		for( unsigned i = 0; i < m_FrameCount; ++i )
		{
			m_Frames[i].timeMS = ReadUInt32( &m_pBuffer );

			for( unsigned j = 0; j < m_NodeCount; ++j )
			{
				m_Frames[i].nodes[j].position.x = ReadFloat( &m_pBuffer );
				m_Frames[i].nodes[j].position.y = ReadFloat( &m_pBuffer );
				m_Frames[i].nodes[j].position.z = ReadFloat( &m_pBuffer );

				m_Frames[i].nodes[j].rotation.x = ReadFloat( &m_pBuffer );
				m_Frames[i].nodes[j].rotation.y = ReadFloat( &m_pBuffer );
				m_Frames[i].nodes[j].rotation.z = ReadFloat( &m_pBuffer );
				m_Frames[i].nodes[j].rotation.w = ReadFloat( &m_pBuffer );	
			}

			for( unsigned j = 0; j < m_VertexCount; ++j )
			{
				m_Frames[i].vertices[j * 3 + 0] = ReadFloat( &m_pBuffer );
				m_Frames[i].vertices[j * 3 + 1] = ReadFloat( &m_pBuffer );
				m_Frames[i].vertices[j * 3 + 2] = ReadFloat( &m_pBuffer );
			}
		}
		SetRange(0, m_FrameCount - 1);
		m_TimeMS = 0;

		return initWithTexture(pTexture, rect);
	}

	return false;
}

void Sprite3D::SetRange( int start, int end )
{
	m_FrameStart = start;
	m_FrameEnd = end;
}

void Sprite3D::GetVerticesAt( int timeMS )
{
	int frameA = -1;
	int frameB = -1;
	float interpolation;

	GetInterpolationValues( timeMS ,frameA, frameB, interpolation );

	assert( frameA != -1 && frameB != -1 );

	if( frameA == frameB )
		BuildTweenFrame( frameA, frameB, 0 );	
	else BuildTweenFrame( frameA, frameB, interpolation );
}

void Sprite3D::GetInterpolationValues( int timeMS, int & frameA, int & frameB, float & interpolation ) const
{
	if( m_FrameCount == 1 )
	{
		frameA = frameB = 0;
		interpolation = 0;
	}
	else
	{
		const int TimeMaxMS = m_Frames[m_FrameCount - 1].timeMS;

		if( timeMS > TimeMaxMS )
			timeMS = timeMS % TimeMaxMS;

		frameA = -1;
		frameB = -1;

		for( unsigned i = 0; i < m_FrameCount; ++i )
		{
			if( m_Frames[i].timeMS >= timeMS )
			{
				if( i == 0 )
				{
					frameA = i;
					frameB = i;
					break;
				}
				else
				{
					frameA = i -1;
					frameB = i;
					break;
				}
			}
		}

		if( frameA == frameB )
			interpolation = 0;
		else interpolation = (float)( timeMS - (float)m_Frames[frameA].timeMS ) / (float)( m_Frames[frameB].timeMS - m_Frames[frameA].timeMS );
	}
}

void Sprite3D::BuildTweenFrame( int frameA, int frameB, float interpolation ) 
{
	if( interpolation <= 0 )
		frameB = frameA;
	else if( interpolation >= 1 )
		frameA = frameB;

	const Frame * pFrameA = &m_Frames[frameA];
	const Frame * pFrameB = &m_Frames[frameB];

	if( pFrameA == pFrameB )
	{
		for( unsigned i = 0; i < m_VertexCount * 3; ++i )
		{
			m_BufferVertices[i] = pFrameA->vertices[i];
		}
	}
	else
	{
		const float Inverse = 1.0f - interpolation;

		for( unsigned i = 0; i < m_VertexCount * 3; ++i )
		{
			const float v0 = pFrameA->vertices[i];
			const float v1 = pFrameB->vertices[i] ;

			m_BufferVertices[i] = v0 * Inverse + v1 * interpolation;
		}

	}
}

void Sprite3D::ComputeBounds( void )
{
	m_Minimum.x = 0;
	m_Minimum.y = 0;
	m_Minimum.z = 0;

	m_Maximum.x = 0;
	m_Maximum.y = 0;
	m_Maximum.z = 0;


	for( unsigned i = 0; i < m_VertexCount; ++i )
	{
		float x = m_Frames[0].vertices[i * 3 + 0];
		float y = m_Frames[0].vertices[i * 3 + 1];
		float z = m_Frames[0].vertices[i * 3 + 2];

		if( x < m_Minimum.x )
			m_Minimum.x = x;

		if( y < m_Minimum.y )
			m_Minimum.y = y;

		if( z < m_Minimum.z )
			m_Minimum.z = z;

		if( x > m_Maximum.x )
			m_Maximum.x = x;

		if( y > m_Maximum.y )
			m_Maximum.y = y;

		if( z > m_Maximum.z )
			m_Maximum.z = z;
	}

	m_Center.x = ( m_Minimum.x + m_Maximum.x ) / 2.f;
	m_Center.y = ( m_Minimum.y + m_Maximum.y ) / 2.f;
	m_Center.z = ( m_Minimum.z + m_Maximum.z ) / 2.f;

	float maximumDimension = 0;

	if( abs( m_Maximum.x - m_Minimum.x ) > maximumDimension )
		maximumDimension = abs( m_Maximum.x - m_Minimum.x );

	if( abs( m_Maximum.y - m_Minimum.y ) > maximumDimension )
		maximumDimension = abs( m_Maximum.y - m_Minimum.y );

	if( abs( m_Maximum.z - m_Minimum.z ) > maximumDimension )
		maximumDimension = abs( m_Maximum.z - m_Minimum.z );

	m_NormalizedScale = ( 1.f / maximumDimension );
}